home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.lang.c++
- Path: netcom.com!marnold
- From: marnold@netcom.com (Matt Arnold)
- Subject: [Q] handle/body idiom; downcasting required?
- Message-ID: <marnoldDpsMDt.H6B@netcom.com>
- Organization: NETCOM On-line Communication Services (408 261-4700 guest)
- Distribution: na
- Date: Sat, 13 Apr 1996 09:01:05 GMT
- Sender: marnold@netcom19.netcom.com
-
- Hi,
-
- Say I want to define some classes Bar and Foo, whose implemtation varies
- according to appropriateness of the implementation for a given condition,
- OS platform, or whatever; the point is I want the implementation to vary
- independent of the interface's of some classes Bar and Foo, for instance,
- that client's will use. That is, client's will use Bar and Foo unaware
- of how they are actually implemented.
-
- So, I use the common handle/body design pattern wherein "handle" classes
- provide an interface for client's and "body" classes provide an interface
- for the handles to implement the required functionality. Client's call
- the handles, unaware of exactly which body services the call.
-
- In my example, this would usually by accomplished by creating concrete
- handle classes Bar and Foo and abstract body classes AbstractBarImp and
- AbstractFooImp. Bar and Foo contain pointers to their appropriate abstract
- implementation class and set them to point to instances of concrete classes,
- which provide specific implementations, derived from the abstract bases.
-
- The problem arises when one or more of the concrete implementations need
- access to another one of the concrete implementations say, to perform some
- interaction specific only to the two concrete implementations. This
- interaction is not expressed in the handle or abstract body class interfaces
- since it does not belong there.
-
- How does one accomplish this using the standard handle/body arrangement?
- See the following sample code and final comment in ConcreteFooImp::UseBar(),
- which wants to interact with a ConcreteFooImp, but doesn't seem to have the
- appropriate types available.
-
-
- // generic implementation interfaces ("body" classes)...
-
- class AbstractBarImp {
- public:
- virtual void DoSomeFunc() = 0;
- };
-
- class AbstractFooImp {
- public:
- virtual void DoUseBar(AbstractBarImp* imp) = 0;
- };
-
-
- // this is what client sees ("handle" classes)
-
- class Bar {
- public:
- void SomeFunc() {
- imp->DoSomeFunc();
- }
-
- private:
- AbstractBarImp* imp;
- };
-
- class Foo {
- public:
- void UseBar(Bar* bar) {
- imp->DoUseBar(bar->imp);
- }
-
- private:
- AbstractFooImp* imp;
- };
-
-
- // this is what implementor creates (concrete versions of body classes)
-
- class ConcreteBarImp: public AbstractBarImp {
- public:
- void DoSomeFunc() {
- // fine; self-contained
- }
-
- void UseMe() {
- }
- };
-
- class ConcreteFooImp: public AbstractFooImp {
- public:
- void DoUseBar(AbstractBarImp* imp) {
- // problem; how to get access to a ConcreteBarImp* without
- // downcasting ?
- //
- // for example, how can DoUseBar() call member
- // ConcreteBarImp()::UseMe() ?
- //
- // (and I don't want to add add virtual AbstractBarImp::UseMe()
- // because this member may not be appropriate for the other
- // concrete AbstractBarImp derivations)
- }
- };
-
-
- Example of where this is a real problem; Say I used the above Bar/Foo-like
- arrangment for Window and Image classes which had specific implementations
- for different platforms (WinWindowImp, MacWindowImp, WinImageImp,
- MacImageImp, etc.). And say there existed a member...
-
- Window::DrawImage(Image* image);
-
- ...which ends up, in the Windows version, calling...
-
- WinWindowImp::DrawImage(AbstractImageImp* image);
-
- Well, WinWindowImp::DrawImage()'s code really wants to deal with a
- WinImageImp*, not an AbstractImageImp*. In fact, WinWindowImp and
- WinImageImp are probably written with each other in mind and require
- specific interactions not part of (and not appropriate for) the
- AbstractWindowImp and AbstractImageImp interfaces. I am at a loss right
- now of how to alter the handle/body idiom to make this work cleanly (ie,
- without downcasting).
-
-
- My conslusion at the moment seems to be that the drawback to the handle/body
- idiom that fact that everthing must be done through abstract interfaces else,
- if and when you need specifics, you have to downcast in your concrete
- classes.
-
- I have the book "Design Patterns" and it covers this idiom, including examples
- very similar to this. However, it appears that the book glosses over details
- such as I have described. The examples in the book seem to assume nothing
- more than the concrete implementations being fully self-contained and whose
- interactions, if any, are handled only abstractly. However, this immediately
- seems to me like it would be very uncommon.
-
- Thanks for any insights,
- -------------------------------------------------------------------------
- Matt Arnold | | ||| | |||| | | | || ||
- marnold@netcom.com | | ||| | |||| | | | || ||
- Boston, MA | 0 | ||| | |||| | | | || ||
- 617.389.7384 (h) 617.576.2760 (w) | | ||| | |||| | | | || ||
- C++, MIDI, Win32/95 developer | | ||| 4 3 1 0 8 3 || ||
- -------------------------------------------------------------------------
-
-